'''
Created on Aug 26, 2011

@author: nktran
'''
from constant import BE, RULE_THRESHOLD, VERBS, EXACT_WEIGHT, LEFT_WEIGHT,\
    RIGHT_WEIGHT, INST_THRESHOLD
import google_fetcher
import time
import random 

ALG = 'simple'
#ALG = 'googleapi'

def get_left_count(example, rule):
    """
    Return the number times example instantiated rule occurs on the web
    
    @param rule: the rule need to evaluate
    @param seeds: a list of seeds need to be assessed          
    """
    count = 0
    has_be = rule.find('BE') != -1
    rule = rule.replace('Y', '').strip()
    rule = '"' + rule + '"'
    
    query = rule.replace('X', example[0].strip())
    for v in VERBS.keys():
        if query.find(v) != -1:
            verb = v
    if has_be:
        query = query.replace(verb, VERBS[verb][2])
    elif example[2].find('1') != -1:
        query = query.replace(verb, VERBS[verb][1])
        
    if has_be:
        if example[2].find('1') != -1:
            query1 = query.replace('BE', BE[0])
            count = count + get_count(query1)
            query2 = query.replace('BE', BE[2])
            count = count + get_count(query2)
        else:
            query1 = query.replace('BE', BE[1])
            count = count + get_count(query1)
            query2 = query.replace('BE', BE[3])
            count = count + get_count(query2)
    else:
        count = count + get_count(query)
            
    return count
                

def get_right_count(example, rule):
    """
    Return the number times example instantiated rule occurs on the web
    
    @param rule: the rule need to evaluate
    @param seeds: a list of seeds need to be assessed      
    """
    count = 0
    has_be = rule.find('BE') != -1
    rule = rule.replace('X','').strip()
    rule = '"' + rule + '"'
    
    query = rule.replace('Y', example[1].strip())
            
    for v in VERBS.keys():
        if query.find(v) != -1:
            verb = v
    if has_be:
        query = query.replace(verb, VERBS[verb][2])
        for i in range(4):
            query1 = query.replace('BE', BE[i])
            count = count + get_count(query1)
    else:
        for i in range(3):
            query1 = query.replace(verb, VERBS[verb][i])
            count = count + get_count(query1)            
    
    return count
    
def get_exact_count(example, rule):
    """
    Return the number times example instantiated rule occurs on the web
    
    @param rule: the rule need to evaluate
    @param seeds: a list of seeds need to be assessed  
    """
    count = 0    
    has_be = rule.find('BE') != -1    
    rule = '"' + rule + '"'

    query = rule.replace('X', example[0].strip())
    query = query.replace('Y', example[1].strip())
    for v in VERBS.keys():
        if query.find(v) != -1:
            verb = v
    if has_be:
        query = query.replace(verb, VERBS[verb][2])
    elif example[2].find('1') != -1:
        query = query.replace(verb, VERBS[verb][1])     
    if has_be:
        if example[2].find('1') != -1:
            query1 = query.replace('BE', BE[0])
            count = count + get_count(query1)
            query2 = query.replace('BE', BE[2])
            count = count + get_count(query2)
        else:
            query1 = query.replace('BE', BE[1])
            count = count + get_count(query1)
            query2 = query.replace('BE', BE[3])
            count = count + get_count(query2)
    else:
        count = count + get_count(query)
    
    return count         

def get_count(query):
    """
    """
    if ALG == 'simple':
        time.sleep(5)
        return google_fetcher.get_number_results(query)
    elif ALG == 'googleapi':
        return google_fetcher.get_results_with_googleapi(query)

    return 0

def assess_instance(example, rule):
    """
    Assess whether an instance is correct or not
    
    @param example: example
    @param rule: rule
    @var exact_count: count the number times that a rule occurs on the web
    if we instantiate X and Y by example
    @var left_count: count the number times that a rule occurs on the web
    if we instantiate X by example
    @var right_count: count the number times that a rule occurs on the web
    if we instantiate Y by example       
    """
    exact_count = get_exact_count(example, rule)
    left_count = get_left_count(example, rule)
    right_count = get_right_count(example, rule)
    
    if EXACT_WEIGHT * exact_count + LEFT_WEIGHT * left_count + \
                    RIGHT_WEIGHT * right_count > INST_THRESHOLD:
        fout = open('example0.out', 'a')
        try:
            fout.write("(%s,%s)\n" % (example[0], example[1]))
        finally:
            fout.close()
    
    print "%s\n%s" % (example, rule)
    print "%d\n%d\n%d\n" % (exact_count, left_count, right_count)
    
def para_eval(rfile, efile):
    """
    Evaluate all rules in the rfile according to examples in efile
    A rule is consider as being correct if number examples instantiated are correct
    
    @param rfile: rule file
    @param efile: example file   
    """
    rules = _get_rule(rfile)
    examples = _get_example(efile)
    
    for rule in rules:
        number_correct_example = 0
        fout = open('example0.out', 'a')
        try:
            fout.write("RULE: %s\n" % rule)
        finally:
            fout.close()
        for example in examples:            
            if assess_instance(example, rule):
                number_correct_example += 1
            time.sleep(random.randint(10,20))
        time.sleep(random.randint(20,30))
        if number_correct_example * 1.0 / len(examples) >= RULE_THRESHOLD:
            print "%s is correct!"
                
def _get_example(fname):
    """
    Return all instances needed to assess
    
    @param fname: file name
    @return: list of instances 
    """
    inst = list()
    fin = open(fname, 'r')    
    try:
        lines = fin.read().split('\n')
        slotX = slotY = typeXY = ""
        for line in lines[1:]:
            if line.find("X=") != -1:
                slotX = line[2:].strip()
            if line.find("Y=") != -1:
                slotY = line[2:].strip()
            if line.find("TYPE=") != -1:
                typeXY = line[5:]
                inst.append((slotX, slotY, typeXY))
    finally:
        fin.close()
    return inst
    
def _get_rule(fname):
    """
    Return all rules need to evaluate
    
    @param fname: file name
    @return: list of rules
    """ 
    rules = list()
    fin = open(fname, 'r')
    try:
        lines = fin.read().split('\n')
        for line in lines[1:]:
            if line.find("###") != -1:
                break
            if line.find('#') != -1:
                continue
            rules.append(line)
#            if len(rules) > 1:
#                break
    finally:
        fin.close()
        
    return rules
    
if __name__ == '__main__':
    para_eval('rules.0', 'example.0')